using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace Rotempco.Core.Logic
{
    public class CancelWorker
    {
        public bool CancellationPending { get; set; }
    }

    public abstract class AGenericBackgroundWorker
    {
        protected BackgroundWorker _BackgroundWorker;
        protected CancelWorker _CancelWorker;

        public void Cancel()
        {
            if (_CancelWorker == null)
                throw new Exception("Cancellation not supported");

            _CancelWorker.CancellationPending = true;
        }
    }

    public class GenericBackgroundWorker : AGenericBackgroundWorker
    {
        protected Action _DoWork;
        protected Action<CancelWorker> _DoWorkCancel;

        public GenericBackgroundWorker(Action doWork)
        {
            _DoWork = doWork;

            StartBackgroundWorker();
        }

        public GenericBackgroundWorker(Action<CancelWorker> doCancelAbleWorker)
        {
            _CancelWorker = new CancelWorker();
            _DoWorkCancel = doCancelAbleWorker;

            StartBackgroundWorker();
        }

        private void StartBackgroundWorker()
        {
            _BackgroundWorker = new BackgroundWorker();
            _BackgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorkerGeneric_DoWork);
            _BackgroundWorker.RunWorkerAsync();
        }

        private void backgroundWorkerGeneric_DoWork(object sender, DoWorkEventArgs e)
        {
            if (_DoWork != null)
                _DoWork();
            else if (_DoWorkCancel != null)
                _DoWorkCancel(_CancelWorker);
        }
    }

    public class GenericBackgroundWorkerResult<Result> : AGenericBackgroundWorker
    {
        private Func<Result> _DoWork;
        protected Func<CancelWorker, Result> _DoWorkCancel;
        private Action<Result> _Completed;

        public GenericBackgroundWorkerResult(Func<Result> doWork, Action<Result> completed)
        {
            _DoWork = doWork;
            _Completed = completed;

            StartBackgroundWorker();
        }

        public GenericBackgroundWorkerResult(Func<CancelWorker, Result> doCancelAbleWorker, Action<Result> completed)
        {
            _CancelWorker = new CancelWorker();
            _DoWorkCancel = doCancelAbleWorker;
            _Completed = completed;

            StartBackgroundWorker();
        }

        private void StartBackgroundWorker()
        {
            _BackgroundWorker = new BackgroundWorker();
            _BackgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorkerGeneric_DoWork);
            _BackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorkerGeneric_RunWorkerCompleted);
            _BackgroundWorker.RunWorkerAsync();
        }

        private void backgroundWorkerGeneric_DoWork(object sender, DoWorkEventArgs e)
        {
            if (_DoWork != null)
                e.Result = _DoWork();
            else if (_DoWorkCancel != null)
                e.Result = _DoWorkCancel(_CancelWorker);
        }

        private void backgroundWorkerGeneric_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            _Completed((Result)e.Result);
        }
    }

    public class GenericBackgroundWorker<Argument> : AGenericBackgroundWorker
    {
        private Action<Argument> _DoWork;
        private Action<CancelWorker, Argument> _DoWorkCancel;

        public GenericBackgroundWorker(Action<Argument> doWork, Argument argument)
        {
            _DoWork = doWork;

            StartBackgroundWorker(argument);
        }

        public GenericBackgroundWorker(Action<CancelWorker, Argument> doWorkCancel, Argument argument)
        {
            _CancelWorker = new CancelWorker();
            _DoWorkCancel = doWorkCancel;

            StartBackgroundWorker(argument);
        }

        private void StartBackgroundWorker(Argument argument)
        {
            _BackgroundWorker = new BackgroundWorker();
            _BackgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorkerGeneric_DoWork);
            _BackgroundWorker.RunWorkerAsync(argument);
        }

        private void backgroundWorkerGeneric_DoWork(object sender, DoWorkEventArgs e)
        {
            if (_DoWork != null)
                _DoWork((Argument)e.Argument);
            else if (_DoWorkCancel != null)
                _DoWorkCancel(_CancelWorker, (Argument)e.Argument);
        }
    }

    public class GenericBackgroundWorker<Argument, Result> : AGenericBackgroundWorker
    {
        private Func<Argument, Result> _DoWork;
        private Func<Argument, CancelWorker, Result> _DoWorkCancel;
        private Action<Result> _Completed;

        public GenericBackgroundWorker(Func<Argument, Result> doWork, Action<Result> completed, Argument argument)
        {
            _DoWork = doWork;
            _Completed = completed;

            StartBackgroundWorker(argument);
        }

        public GenericBackgroundWorker(Func<Argument, CancelWorker, Result> doWorkCancel, Action<Result> completed, Argument argument)
        {
            _CancelWorker = new CancelWorker();
            _DoWorkCancel = doWorkCancel;
            _Completed = completed;

            StartBackgroundWorker(argument);
        }

        private void StartBackgroundWorker(Argument argument)
        {
            _BackgroundWorker = new BackgroundWorker();
            _BackgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorkerGeneric_DoWork);
            _BackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorkerGeneric_RunWorkerCompleted);
            _BackgroundWorker.RunWorkerAsync(argument);
        }

        private void backgroundWorkerGeneric_DoWork(object sender, DoWorkEventArgs e)
        {
            if (_DoWork != null)
                e.Result = _DoWork((Argument)e.Argument);
            else if (_DoWorkCancel != null)
                e.Result = _DoWorkCancel((Argument)e.Argument, _CancelWorker);
        }

        private void backgroundWorkerGeneric_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            _Completed((Result)e.Result);
        }
    }

    public class GenericBackgroundWorker<Argument, Progress, Result> : AGenericBackgroundWorker
    {
        private Func<Argument, Action<Progress>, Result> _DoWork;
        protected Func<Argument, Action<Progress>, CancelWorker, Result> _DoWorkCancel;
        private Action<Result> _Completed;
        private Action<Progress> _Progress;
        private Action<Progress> _InternalProgress;

        private void ProgressNow(Progress progress)
        {
            _BackgroundWorker.ReportProgress(0, progress);
        }

        public GenericBackgroundWorker(Func<Argument, Action<Progress>, Result> doWork, Action<Result> completed, Action<Progress> progress, Argument argument)
        {
            _DoWork = doWork;
            _Completed = completed;
            _Progress = progress;
            _InternalProgress = ProgressNow;

            StartBackgroundWorker(argument);
        }

        public GenericBackgroundWorker(Func<Argument, Action<Progress>, CancelWorker, Result> doWorkCancel, Action<Result> completed, Action<Progress> progress, Argument argument)
        {
            _CancelWorker = new CancelWorker();
            _DoWorkCancel = doWorkCancel;
            _Completed = completed;
            _Progress = progress;
            _InternalProgress = ProgressNow;

            StartBackgroundWorker(argument);
        }

        private void StartBackgroundWorker(Argument argument)
        {
            _BackgroundWorker = new BackgroundWorker();
            _BackgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorkerGeneric_DoWork);
            _BackgroundWorker.WorkerReportsProgress = true;
            _BackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorkerGeneric_ProgressChanged);
            _BackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorkerGeneric_RunWorkerCompleted);
            _BackgroundWorker.RunWorkerAsync(argument);
        }

        private void backgroundWorkerGeneric_DoWork(object sender, DoWorkEventArgs e)
        {
            if (_DoWork != null)
                e.Result = _DoWork((Argument)e.Argument, _InternalProgress);
            else if (_DoWorkCancel != null)
                e.Result = _DoWorkCancel((Argument)e.Argument, _InternalProgress, _CancelWorker);
        }

        private void backgroundWorkerGeneric_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            _Progress((Progress)e.UserState);
        }

        private void backgroundWorkerGeneric_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            _Completed((Result)e.Result);
        }
    }
}
